package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import org.apache.commons.lang.CharSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;

@Component
@SuppressWarnings("all")
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private AntPathMatcher antPathMatcher=new AntPathMatcher();


    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${authUrls.url}")
    public String authUrls;

    /**
     * 用户认证整合网关
     * @param exchange
     * @param chain
     * @return
     *
     * 处理思路：
     * 拦截指定需要认证的资源
     *     1.内部访问的资源
     *     api/product/inner/getTrademark/{tmId}
     *     /** /inner/ **
     *     只允许服务器内部服务调用
     *     2.必须要认证才能访问的资源
     *     /** /auth / **
     *     例如：/api/order/auth/{page}/{limit}
     *     判断是否登录
     *     提示：请求登录
     *
     *     3.web资源访问
     *     http://list.gmall.com/list.html
     *     list.html login.html ....
     *     白名单形式
     *
     *
     *
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取用户请求
        ServerHttpRequest request = exchange.getRequest();
        //获取用户响应信息
        ServerHttpResponse response = exchange.getResponse();

        //获取path路径
        //http://api.gmall.com
        ///api/user/passport/logout
        String path = request.getURI().getPath();
        System.out.println(path);
        //1.拦截内部接口 /**/inner/**
        if(antPathMatcher.match("/**/inner/**",path)){

            //直接拒绝访问
            return out(response, ResultCodeEnum.PERMISSION);

        }

        //获取用户id
        String userId= this.getUserId(request);

        //判断用户是否登录--拦截需要认证的资源
        if(antPathMatcher.match("/**/auth/**",path)){

            //判断用户未登录，才拦截，并提示
            if(StringUtils.isEmpty(userId)){

                return out(response,ResultCodeEnum.PERMISSION);
            }


        }

        //白名单--web资源

        if(!StringUtils.isEmpty(authUrls)){

            //截取遍历白名单 trade.html,myOrder.html ,list.html
            for (String url : authUrls.split(",")) {
                // /list.html
                if(path.indexOf(url)!=-1&& StringUtils.isEmpty(userId)){
                    //303状态码表示由于请求对应的资源存在着另一个URI，应使用重定向获取请求的资源
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    response.getHeaders().set(HttpHeaders.LOCATION,"http://www.gmall.com/login.html?originUrl="+request.getURI());
                    return response.setComplete();


                }



            }

//            //trade.html,myOrder.html ,list.html  /login.html -1  list.hml
//            // /list.html  list.html
//            String paths = path.substring(1);
//            if(!StringUtils.isEmpty(paths)&&authUrls.indexOf(paths)!=-1 &&StringUtils.isEmpty(userId)){
//
//                //303状态码表示由于请求对应的资源存在着另一个URI，应使用重定向获取请求的资源
//                response.setStatusCode(HttpStatus.SEE_OTHER);
//
//
//                response.getHeaders().set(HttpHeaders.LOCATION,"http://www.gmall.com/login.html?originUrl="+request.getURI());
//
//
//
//                return response.setComplete();
//            }




        }


        //获取临时用户id
        String userTempId=getUserTempId(request);




        //判断
        if(!StringUtils.isEmpty(userId)||!StringUtils.isEmpty(userTempId)){

            if(!StringUtils.isEmpty(userId)){
                //请求对象中设置头信息
                request.mutate().header("userId",userId).build();

            }

            if(!StringUtils.isEmpty(userTempId)){
                //请求对象中设置头信息
                request.mutate().header("userTempId",userTempId).build();

            }

            return chain.filter(exchange.mutate().request(request).build()) ;

        }




        return chain.filter(exchange);
    }

    /**
     * 获取临时id
     * @param request
     * @return
     */
    private String getUserTempId(ServerHttpRequest request) {

        String userTempId="";
        //从头信息获取
        userTempId= request.getHeaders().getFirst("userTempId");
        //判断
        if(StringUtils.isEmpty(userTempId)){

            MultiValueMap<String, HttpCookie> cookies = request.getCookies();
            //判断
            if(cookies!=null){

                //获取userTempId的cookie
                HttpCookie cookie = cookies.getFirst("userTempId");
                //判断
                if(cookie!=null){

                    userTempId=cookie.getValue();
                }

            }

        }


        return userTempId;
    }



    /**
     * 获取用户id
     * @param request
     * @return
     *
     * 认证用户是否登录：
     *  1."" :没有登录
     *  2. -1 :非法盗用
     *  3.userId :用户已经在登录状态
     *
     *
     *
     */
    private String getUserId(ServerHttpRequest request) {

        String token = "";
        //获取token
        List<String> tokenList = request.getHeaders().get("token");
        //判断
        if(!CollectionUtils.isEmpty(tokenList)){

            token=tokenList.get(0);

        }else{
            //cookie
            MultiValueMap<String, HttpCookie> cookies = request.getCookies();
            //判断
            if(cookies!=null){

                HttpCookie cookie = cookies.getFirst("token");
                if(cookie!=null){

                    token=cookie.getValue();
                }

            }


        }

        //判断是否获取到了token
        if(!StringUtils.isEmpty(token)){

            //请求redis获取数据
            String strJson = (String) redisTemplate.opsForValue().get("user:login:" + token);
            //转换对象
            JSONObject jsonObject = JSONObject.parseObject(strJson);


            //获取ip
            String ip = jsonObject.getString("ip");
            //校验
            if(!IpUtil.getGatwayIpAddress(request).equals(ip)){
                //非法盗用
                return "-1";
            }

            return jsonObject.getString("userId");



        }else{

            //用户未登录
            return "";

        }


    }

    /**
     * 设置响应内容
     * @param response
     * @param permission
     * @return
     */
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum permission) {

        //设置同意异常结果
        Result<Object> result = Result.build(null, permission);
        //转换成字符串
        String message = JSONObject.toJSONString(result);
        //转换成自己数据
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        DataBuffer wrap = response.bufferFactory().wrap(bytes);
        //中文乱码处理
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(wrap));
    }


    /**
     * 优先级
     * 指定过滤器链中的顺序
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 6;
    }
}
